Skip to content

Protect uncaught_exceptions virtual table against the crash path - #5028

Closed
frankgh wants to merge 1 commit into
apache:trunkfrom
frankgh:CASSANDRA-21578
Closed

Protect uncaught_exceptions virtual table against the crash path#5028
frankgh wants to merge 1 commit into
apache:trunkfrom
frankgh:CASSANDRA-21578

Conversation

@frankgh

@frankgh frankgh commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Fixes three issues in ExceptionsTable, which records every uncaught exception from JVMStabilityInspector's central stability path:

  • Guard the persist(t) call so a throw can't skip inspectThrowable's disk_failure_policy / OOM die handling.
  • Drain preInitialisationBuffer under its monitor in flush() to avoid a ConcurrentModificationException that could abort node startup.
  • Bound preInitialisationBuffer so a startup exception storm (or a tool context that never flushes) can't retain stack traces without limit.

patch by Francisco Guerrero; reviewed by TBD for CASSANDRA-21578

Fixes three issues in ExceptionsTable, which records every uncaught
exception from JVMStabilityInspector's central stability path:

- Guard the persist(t) call so a throw can't skip inspectThrowable's
  disk_failure_policy / OOM die handling.
- Drain preInitialisationBuffer under its monitor in flush() to avoid a
  ConcurrentModificationException that could abort node startup.
- Bound preInitialisationBuffer so a startup exception storm (or a tool
  context that never flushes) can't retain stack traces without limit.

patch by Francisco Guerrero; reviewed by TBD for CASSANDRA-21578
// otherwise add() during iteration and trigger a ConcurrentModificationException, which would propagate out of
// setupVirtualKeyspaces() and abort node startup.
List<ExceptionRow> drained;
synchronized (preInitialisationBuffer)

@frankgh frankgh Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iteration must be synchronized for arrays wrapped with Collections.synchronizedList. Here's an excerpt from the Collections.synchronizedList javadoc:

     * It is imperative that the user manually synchronize on the returned
     * list when traversing it via {@link Iterator}, {@link Spliterator}
     * or {@link Stream}:
     * <pre>
     *  List list = Collections.synchronizedList(new ArrayList());
     *      ...
     *  synchronized (list) {
     *      Iterator i = list.iterator(); // Must be in synchronized block
     *      while (i.hasNext())
     *          foo(i.next());
     *  }
     * </pre>

// together under the list monitor so concurrent persist() calls cannot race past the cap.
synchronized (preInitialisationBuffer)
{
if (preInitialisationBuffer.size() < PRE_INITIALISATION_BUFFER_CAPACITY)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we want to avoid this growing bigger than the 1000 limit we had set above in the ctor in the original patch

ExceptionsTable.persist(t);
// Recording the exception for observability must never preempt the stability handling below (the
// disk_failure_policy / OOM "die" actions in inspectThrowable). Guard it like the StorageMetrics increment above.
try { ExceptionsTable.persist(t); } catch (Throwable ignore) { /* observability only, must not throw here */ }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should never allow a failure here prevent us from processing the exception, we follow the same pattern as line 74

@smiklosovic smiklosovic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for making this more robust

@frankgh

frankgh commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

Closed via 1d29b33

@frankgh frankgh closed this Aug 16, 2026
@frankgh
frankgh deleted the CASSANDRA-21578 branch August 16, 2026 22:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants